//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2013 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_AUTO_DEFINES_H_
#define _BUOLA_AUTO_DEFINES_H_

///\addtogroup utility
///@{

namespace buola { 
    
namespace detail {

    template<typename tEnum>
    struct CEnumClassAndResult
    {
        template<typename tInt>
        explicit CEnumClassAndResult(tInt pEnum)
            :   mEnum((tEnum)pEnum)
        {}
            
        operator bool()             {   return mEnum!=tEnum(0); }
        operator tEnum()            {   return mEnum;           }
        bool operator!()            {   return mEnum==tEnum(0); }
        
    private:
        tEnum mEnum;
    };

/*namespace detail*/ } 

/*namespace buola*/ }

///\name Attributes
//@{

///declares a variable as possibly unused to avoid warnings
#define ATTRIBUTE_UNUSED __attribute__((unused))

///don't use any padding between the members of a struct or union
#define ATTRIBUTE_PACKED __attribute__((packed))

//@}

///\name Enumerations
//@{

#define DECLARE_ENUM_BITOPS_INTERNAL(e,qual,and_return_type)                                                        \
    qual and_return_type operator&(e pLH,e pRH)     {   return and_return_type(int(pLH)&int(pRH));    }             \
    qual e operator|(e pLH,e pRH)     {   return e(int(pLH)|int(pRH));    }                                         \
    qual e operator^(e pLH,e pRH)     {   return e(int(pLH)^int(pRH));    }                                         \
    qual e &operator&=(e& pLH,e pRH)  {   return pLH=pLH&pRH; }                                                     \
    qual e &operator|=(e& pLH,e pRH)  {   return pLH=pLH|pRH; }                                                     \
    qual e &operator^=(e& pLH,e pRH)  {   return pLH=pLH^pRH; }                                                     \
    qual e operator~(e pLH)           {   return e(~int(pLH));        }

#define RETURN_TYPE(e) ::buola::detail::CEnumClassAndResult<e>
    
///makes it possible to use bit operators with enumeration e
#define DECLARE_ENUM_BITOPS(e) DECLARE_ENUM_BITOPS_INTERNAL(e,inline,e)

///makes it possible to use bit operators with enumeration class e
#define DECLARE_ENUM_CLASS_BITOPS(e) DECLARE_ENUM_BITOPS_INTERNAL(e,inline,::buola::detail::CEnumClassAndResult<e>)                                 \

///makes it possible to use bit operators with enumeration e
///
///This version should be used when the enumeration is declared inside a class
#define DECLARE_FRIEND_ENUM_BITOPS(e) DECLARE_ENUM_BITOPS_INTERNAL(e,inline friend,e)

///makes it possible to use bit operators with enumeration class e
///
///This version should be used when the enumeration is declared inside a class
#define DECLARE_FRIEND_ENUM_CLASS_BITOPS(e) DECLARE_ENUM_BITOPS_INTERNAL(e,inline friend,                           \
                                                                         ::buola::detail::CEnumClassAndResult<e>)

//@}

///\name Names
//@{

///declares a new name that can be used for constructor, template and function selection

///This actually declares two entities:
/// - \c Nname is a type which can be used as a paremeter when declaring the function
/// - \c nname is an object of that type, which can be used to select an overload of a function
#define DECLARE_NAME(name)                          \
    struct N##name {};                              \
    static constexpr N##name n##name ATTRIBUTE_UNUSED={};

///declares a new name that can be used for constructor, template and function selection

///This actually declares two entities:
/// - \c Nname is a type which can be used as a paremeter when declaring the function
/// - \c nname is an object of that type, which can be used to select an overload of a function
#define DECLARE_DERIVED_NAME(name, ...)              \
    struct N##name : public __VA_ARGS__ {};          \
    static constexpr N##name n##name ATTRIBUTE_UNUSED={};

//@}

//in case some idiot defined it
#undef NONE

///@}

#endif
